DESeq2 analysis of peak universe (joint peak set called in any
condition, must be called in all three replicates, MACS3)
bw_dir <- "/Volumes/DATA/DATA/Puck/bigwig/"
chromhmm <- "../genome/ESC_10_segments.mm39.bed"
library("wigglescout")
library("ggpubr")
library("ggplot2")
library("DESeq2")
library("dplyr")
library("ggrastr")
clean <- function (fn) {
fn <- gsub(pattern = ".+/", "", x = fn)
fn <- gsub(pattern = ".mm9.+", "", x = fn)
fn <- gsub(pattern = ".mm39.+", "", x = fn)
fn <- gsub(pattern = "_S.+", "", x = fn)
fn <- gsub(pattern = ".scaled.bw", "", x = fn)
fn <- gsub(pattern = ".unscaled.bw", "", x = fn)
fn <- gsub(pattern = "_batch2", "", x = fn)
fn <- gsub(pattern = "-", " ", x = fn)
fn <- gsub(pattern = "_", " ", x = fn)
fn <- gsub(pattern = " HA ", " ", x = fn)
fn <- gsub(pattern = "D1D6", "FANCJ-/-", x = fn)
fn <- gsub(pattern = "P2D2", "DHX36-/-", x = fn)
fn <- gsub(pattern = "P3D4", "FANCJ-/-DHX36-/-", x = fn)
return(fn)
}
BWs <- paste0(bw_dir,list.files(bw_dir,pattern="G4_.+R.\\.bw"))
mypal <-c("cornflowerblue","orange","red2","#505050")
mypal3 <-c("cornflowerblue","cornflowerblue","cornflowerblue","orange","orange","orange","red2","red2","red2","505050","505050","505050")
bw_granges_diff_analysis <- function(granges_c1,
granges_c2,
label_c1,
label_c2,
estimate_size_factors = FALSE,
as_granges = FALSE) {
# Bind first, get numbers after
names_values <- NULL
fields <- names(mcols(granges_c1))
if ("name" %in% fields) {
names_values <- mcols(granges_c1)[["name"]]
granges_c1 <- granges_c1[, fields[fields != "name"]]
}
fields <- names(mcols(granges_c2))
if ("name" %in% fields) {
granges_c2 <- granges_c2[, fields[fields != "name"]]
}
cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))
if (! is.null(names_values)) {
rownames(cts_df) <- names_values
}
# Needs to drop non-complete cases and match rows
complete <- complete.cases(cts_df)
cts_df <- cts_df[complete, ]
values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
cts <- get_nreads_columns(values_df)
condition_labels <- c(rep(label_c1, length(mcols(granges_c1))),
rep(label_c2, length(mcols(granges_c2))))
coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))
dds <- DESeq2::DESeqDataSetFromMatrix(countData = cts,
colData = coldata,
design = ~ condition,
rowRanges = granges_c1[complete, ])
if (estimate_size_factors == TRUE) {
dds <- DESeq2::estimateSizeFactors(dds)
}
else {
# Since files are scaled, we do not want to estimate size factors
sizeFactors(dds) <- c(rep(1, ncol(cts)))
}
dds <- DESeq2::estimateDispersions(dds)
dds <- DESeq2::nbinomWaldTest(dds)
if (as_granges) {
result <- DESeq2::results(dds, format = "GRanges",alpha = 0.01)
if (!is.null(names_values)) {
result$name <- names_values[complete]
}
}
else {
# result <- results(dds, format="DataFrame")
result <- dds
}
result
}
get_nreads_columns <- function(df, length_factor = 100) {
# Convert mean coverages to round integer read numbers
cts <- as.matrix(df)
cts <- as.matrix(cts[complete.cases(cts),])
cts <- round(cts*length_factor)
cts
}
peak_universe <- "../peaks/G4_combined_min3rep.bed"
BWs.WT <- BWs[grep("WT",BWs)]
BWs.FANCJ <- BWs[grep("D1D6",BWs)]
BWs.DHX36 <- BWs[grep("P2D2",BWs)]
BWs.DKO <- BWs[grep("P3D4",BWs)]
# Calculate here some loci or bins
cov.WT <- bw_loci(BWs.WT, loci = peak_universe)
cov.DHX36 <- bw_loci(BWs.DHX36, loci = peak_universe)
cov.FANCJ <- bw_loci(BWs.FANCJ, loci = peak_universe)
cov.DKO <- bw_loci(BWs.DKO, loci = peak_universe)
cov.WT$name <- paste0("peak_",1:length(cov.WT))
cov.DHX36$name <- paste0("peak_",1:length(cov.DHX36))
cov.FANCJ$name <- paste0("peak_",1:length(cov.FANCJ))
cov.DKO$name <- paste0("peak_",1:length(cov.DKO))
diff_DHX36 <- bw_granges_diff_analysis(cov.WT, cov.DHX36,
"WT", "DHX36KO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_FANCJ <- bw_granges_diff_analysis(cov.WT, cov.FANCJ,
"WT", "FANCJ")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_DKO <- bw_granges_diff_analysis(cov.WT, cov.DKO,
"WT", "DKO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
# This takes care of low conts and things like this, but you can also use
# diff_results as is for the things below
lfc_DHX36 <- DESeq2::lfcShrink(diff_DHX36, coef = "condition_WT_vs_DHX36KO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_FANCJ <- DESeq2::lfcShrink(diff_FANCJ, coef = "condition_WT_vs_FANCJ", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_DKO <- DESeq2::lfcShrink(diff_DKO, coef = "condition_WT_vs_DKO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
data_DHX36 <- plotMA(lfc_DHX36, returnData = T)
data_DHX36$lfc <- -data_DHX36$lfc
data_DHX36$mean <- log10(data_DHX36$mean)
data_FANCJ <- plotMA(lfc_FANCJ, returnData = T)
data_FANCJ$lfc <- -data_FANCJ$lfc
data_FANCJ$mean <- log10(data_FANCJ$mean)
data_DKO <- plotMA(lfc_DKO, returnData = T)
data_DKO$lfc <- -data_DKO$lfc
data_DKO$mean <- log10(data_DKO$mean)
ggscatter(data_DHX36,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(limits = c(-10,50)) + scale_y_continuous(limits = c(-10,50)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36_zoom <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_FANCJ,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
data_FANCJ$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_FANCJ$cov.FANCJ <- rowMeans(as.data.frame(cov.FANCJ)[,6:8])
ggscatter(data_FANCJ,x ="cov.WT",y="cov.FANCJ",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_DKO,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_DKO <- rasterize(last_plot(), layers='Point', dpi=600)
data_DKO$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DKO$cov.DKO <- rowMeans(as.data.frame(cov.DKO)[,6:8])
ggscatter(data_DKO,x ="cov.WT",y="cov.DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DKO <- rasterize(last_plot(), layers='Point', dpi=600)
data_DKO$lfc_DHX36 <- data_DHX36$lfc
data_DKO$lfc_FANCJ <- data_FANCJ$lfc
ggscatter(data_DKO,x ="lfc_DHX36",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

plot_LFC_DKO_vs_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_DKO,x ="lfc_FANCJ",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

plot_LFC_DKO_vs_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$lfc_DKO <- data_DKO$lfc
ggscatter(data_DHX36,x ="lfc",y="lfc_DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

bed <- as.data.frame(cov.DHX36)[,1:3]
results_table <- data.frame(chr=bed$seqnames,start=bed$start,end=bed$end,name=cov.WT$name, baseMean=lfc_DKO$baseMean,DHX36=data_DHX36$isDE,FANCJ=data_FANCJ$isDE,DKO=data_DKO$isDE,DHX36lfc=data_DHX36$lfc,FANCJlfc=data_FANCJ$lfc,DKOlfc=data_DKO$lfc,dir=".")
results_table$nonsig <- !(results_table$DHX36 | results_table$FANCJ | results_table$DKO)
results_table$sig <- factor("lowlfc", levels=c("nonsig","lowlfc","FANCJ","DHX36","DKO"))
results_table$sig[(results_table$nonsig)] <- "nonsig"
results_table$sig[(results_table$DKO & results_table$DKOlfc>1)] <- "DKO"
results_table$sig[(results_table$DHX36 & results_table$DHX36lfc>1)] <- "DHX36"
results_table$sig[(results_table$FANCJ & results_table$FANCJlfc>1)] <- "FANCJ"
write.table(results_table,"G4_CnT_combined_peaks_DESeq_results.txt", row.names = F, col.names = T,quote = F, sep = "\t")
DHX36_bed <- results_table[(results_table$DHX36 & results_table$DHX36lfc>1),c(1,2,3,4,9,12)]
write.table(DHX36_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DHX36_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
FANCJ_bed <- results_table[(results_table$FANCJ & results_table$FANCJlfc>1),c(1,2,3,4,10,12)]
write.table(FANCJ_bed,"../peaks/G4_CnT_combined_peaks_DESeq_FANCJ_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
DKO_bed <- results_table[(results_table$DKO & results_table$DKOlfc>1),c(1,2,3,4,11,12)]
write.table(DKO_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
nonsig_bed <- results_table[results_table$nonsig ,c(1,2,3,4,11,12)]
write.table(nonsig_bed,"../peaks/G4_CnT_combined_peaks_DESeq_nonsig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
DKO_bed_top <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc>2 & results_table$baseMean > 100),c(1,2,3,4,11,12)]
write.table(DKO_bed_top,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig_lfc_base_cutoff.bed", row.names = F, col.names = F,quote = F, sep = "\t")
write.table(cbind(results_table[,c(1,2,3)],results_table$sig,as.numeric(results_table$sig),"."),"../peaks/G4_CnT_combined_peaks_DESeq_sig_categories.bed", row.names = F, col.names = F,quote = F, sep = "\t")
library(eulerr)
v <- list(DHX36=DHX36_bed$name,FANCJ=FANCJ_bed$name,DKO=DKO_bed$name)
plot_Venn_all <- plot(euler(v),quantities=T, border="black")
plot_Venn_all

library(eulerr)
DKOneg <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc< -1),c(4)]
v <- list(all=cov.WT$name,DKOneg=DKOneg,DKO=DKO_bed$name)
plot_Venn_DKO <- plot(euler(v),quantities=T)
plot_Venn_DKO

dir.create("./plots",showWarnings = F)
ggsave("plots/peaks_DESeq2_MA_DHX36.pdf",plot_MA_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_FANCJ.pdf",plot_MA_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_DKO.pdf",plot_MA_DKO,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_DHX36.pdf",plot_LFC_DKO_vs_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_FANCJ.pdf",plot_LFC_DKO_vs_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_KOs.pdf",plot_Venn_all,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_DKO_vs_all.pdf",plot_Venn_DKO,width = 4, height= 4)
library(cowplot)
dir.create("./panels",showWarnings = F)
library("cowplot")
p <- ggdraw() +
draw_plot(plot_MA_DHX36, x = 0, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_FANCJ, x = .33, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_DKO, x = 0.66, y = 0.5, width = .33, height = 0.5) +
draw_plot(plot_LFC_DKO_vs_DHX36, x = 0, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_LFC_DKO_vs_FANCJ, x = 0.33, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_Venn_all, x = 0.66, y = 0, width = 0.33, height = 0.5) +
draw_plot_label(label = c("a", "b", "c","d","e","f"), size = 15,
x = c(0, 0.33, 0.66, 0, 0.33, 0.66), y = c(1, 1, 1, 0.5, 0.5, 0.5))
p

ggsave("panels/peaks_DESeq2.pdf",p)
Saving 12 x 8 in image
library(cowplot)
dir.create("./panels",showWarnings = F)
library("cowplot")
p <- ggdraw() +
draw_plot(plot_MA_DHX36, x = 0, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_FANCJ, x = .33, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_DKO, x = 0.66, y = 0.5, width = .33, height = 0.5) +
draw_plot(plot_XY_DHX36, x = 0, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_XY_FANCJ, x = 0.33, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_XY_DKO, x = 0.66, y = 0, width = 0.33, height = 0.5) +
draw_plot_label(label = c("a", "b", "c","d","e","f"), size = 15,
x = c(0, 0.33, 0.66, 0, 0.33, 0.66), y = c(1, 1, 1, 0.5, 0.5, 0.5))
Warning: Removed 36 rows containing missing values (`geom_point()`).Warning: Transformation introduced infinite values in continuous y-axisWarning: Removed 22 rows containing missing values (`geom_point()`).Warning: Transformation introduced infinite values in continuous y-axisWarning: Removed 38 rows containing missing values (`geom_point()`).
p

ggsave("panels/peaks_DESeq2_scatter.pdf",p)
Saving 12 x 8 in image
cov <- cbind( as.data.frame(cov.WT)[,1:8],
as.data.frame(cov.DHX36)[,6:8],
as.data.frame(cov.FANCJ)[,6:8],
as.data.frame(cov.DKO)[,6:8])
colnames(cov) <- c(colnames(cov)[1:5],"WT1","WT2","WT3","DHX1","DHX2","DHX3","FAN1","FAN2","FAN3","DKO1","DKO2","DKO3")
rownames(cov) <- as.data.frame(cov.WT)$name
cov$DHX36_sig <- rownames(cov) %in% DHX36_bed$name
cov$FANCJ_sig <- rownames(cov) %in% FANCJ_bed$name
cov$DKO_sig <- rownames(cov) %in% DKO_bed$name
cov$non_sig <- with(cov, !(DHX36_sig | FANCJ_sig | DKO_sig))
library(reshape2)
mdf <- melt(data.frame(name=rownames(cov),cov[,6:21]))
Using name, DHX36_sig, FANCJ_sig, DKO_sig, non_sig as id variables
mdf <- mdf[mdf$value<500,]
mdf$cond <- "WT"
mdf$cond[grep("DHX",mdf$variable)] <- "DHX36-/-"
mdf$cond[grep("FAN",mdf$variable)] <- "FANCJ-/-"
mdf$cond[grep("DKO",mdf$variable)] <- "DHX36-/-FANCJ-/-"
plot_viol_rep_all_peaks <- ggviolin(mdf, x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_all_peaks

plot_viol_rep_DHX36_peaks <- ggviolin(mdf[mdf$DHX36_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_DHX36_peaks

ggviolin(mdf[mdf$FANCJ_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))

plot_viol_rep_DKO_peaks <- ggviolin(mdf[mdf$DKO_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_DKO_peaks

plot_viol_rep_nonsig_peaks <- ggviolin(mdf[mdf$non_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_nonsig_peaks

ggsave("plots/peaks_DESeq2_viol_rep_all.pdf",plot_viol_rep_all_peaks)
Saving 7 x 7 in image
ggsave("plots/peaks_DESeq2_viol_rep_DKO.pdf",plot_viol_rep_DKO_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_DHX36.pdf",plot_viol_rep_DHX36_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_nonsig.pdf",plot_viol_rep_nonsig_peaks)
sdf <- aggregate(value ~ name + cond, data=mdf, FUN="mean")
sdf$cond <- factor(sdf$cond,levels=c("WT","DHX36-/-","FANCJ-/-","DHX36-/-FANCJ-/-"))
ggviolin(sdf, x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,50))

sdf$DHX36_sig <- sdf$name %in% DHX36_bed$name
sdf$FANCJ_sig <- sdf$name %in% FANCJ_bed$name
sdf$DKO_sig <- sdf$name %in% DKO_bed$name
sdf$DKO_top <- sdf$name %in% DKO_bed_top$name
ggviolin(sdf[sdf$DHX36,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

ggviolin(sdf[sdf$FANCJ_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

plot_viol_DKO_peaks <- ggviolin(sdf[sdf$DKO_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))
plot_viol_DKO_peaks

ggviolin(sdf[sdf$DKO_top,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

LS0tCnRpdGxlOiAiRzQgQ1VUJlRhZyBhbmFseXNpcyBtRVNDIChXVCwgRkFOQ0ogS08sIERIWDM2IEtPLCBES08pIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpTaW1vbiBFbHPDpHNzZXIsIEthcm9saW5za2EgSW5zdGl0dXRldCAoMjAyMykKCiMjIyBERVNlcTIgYW5hbHlzaXMgb2YgcGVhayB1bml2ZXJzZSAoam9pbnQgcGVhayBzZXQgY2FsbGVkIGluIGFueSBjb25kaXRpb24sIG11c3QgYmUgY2FsbGVkIGluIGFsbCB0aHJlZSByZXBsaWNhdGVzLCBNQUNTMykKCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpid19kaXIgPC0gIi9Wb2x1bWVzL0RBVEEvREFUQS9QdWNrL2JpZ3dpZy8iCmNocm9taG1tIDwtICIuLi9nZW5vbWUvRVNDXzEwX3NlZ21lbnRzLm1tMzkuYmVkIgoKbGlicmFyeSgid2lnZ2xlc2NvdXQiKQpsaWJyYXJ5KCJnZ3B1YnIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKCmNsZWFuIDwtIGZ1bmN0aW9uIChmbikgewogIGZuIDwtIGdzdWIocGF0dGVybiA9ICIuKy8iLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICIubW05LisiLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICIubW0zOS4rIiwgIiIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiX1MuKyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi5zY2FsZWQuYnciLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICIudW5zY2FsZWQuYnciLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJfYmF0Y2gyIiwgIiIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiLSIsICIgIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJfIiwgIiAiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIiBIQSAiLCAiICIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiRDFENiIsICJGQU5DSi0vLSIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiUDJEMiIsICJESFgzNi0vLSIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiUDNENCIsICJGQU5DSi0vLURIWDM2LS8tIiwgeCA9IGZuKQogIHJldHVybihmbikKfQoKQldzIDwtIHBhc3RlMChid19kaXIsbGlzdC5maWxlcyhid19kaXIscGF0dGVybj0iRzRfLitSLlxcLmJ3IikpCgpteXBhbCA8LWMoImNvcm5mbG93ZXJibHVlIiwib3JhbmdlIiwicmVkMiIsIiM1MDUwNTAiKQpteXBhbDMgPC1jKCJjb3JuZmxvd2VyYmx1ZSIsImNvcm5mbG93ZXJibHVlIiwiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJvcmFuZ2UiLCJvcmFuZ2UiLCJyZWQyIiwicmVkMiIsInJlZDIiLCI1MDUwNTAiLCI1MDUwNTAiLCI1MDUwNTAiKQpgYGAKCmBgYHtyfQpid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMgPC0gZnVuY3Rpb24oZ3Jhbmdlc19jMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYW5nZXNfYzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2MyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hdGVfc2l6ZV9mYWN0b3JzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc19ncmFuZ2VzID0gRkFMU0UpIHsKCiAgIyBCaW5kIGZpcnN0LCBnZXQgbnVtYmVycyBhZnRlcgogIG5hbWVzX3ZhbHVlcyA8LSBOVUxMCiAgZmllbGRzIDwtIG5hbWVzKG1jb2xzKGdyYW5nZXNfYzEpKQoKICBpZiAoIm5hbWUiICVpbiUgZmllbGRzKSB7CiAgICBuYW1lc192YWx1ZXMgPC0gbWNvbHMoZ3Jhbmdlc19jMSlbWyJuYW1lIl1dCiAgICBncmFuZ2VzX2MxIDwtIGdyYW5nZXNfYzFbLCBmaWVsZHNbZmllbGRzICE9ICJuYW1lIl1dCiAgfQoKICBmaWVsZHMgPC0gbmFtZXMobWNvbHMoZ3Jhbmdlc19jMikpCiAgaWYgKCJuYW1lIiAlaW4lIGZpZWxkcykgewogICAgZ3Jhbmdlc19jMiA8LSBncmFuZ2VzX2MyWywgZmllbGRzW2ZpZWxkcyAhPSAibmFtZSJdXQogIH0KCiAgY3RzX2RmIDwtIGNiaW5kKGRhdGEuZnJhbWUoZ3Jhbmdlc19jMSksIG1jb2xzKGdyYW5nZXNfYzIpKQoKICBpZiAoISBpcy5udWxsKG5hbWVzX3ZhbHVlcykpIHsKICAgIHJvd25hbWVzKGN0c19kZikgPC0gbmFtZXNfdmFsdWVzCiAgfQoKICAjIE5lZWRzIHRvIGRyb3Agbm9uLWNvbXBsZXRlIGNhc2VzIGFuZCBtYXRjaCByb3dzCiAgY29tcGxldGUgPC0gY29tcGxldGUuY2FzZXMoY3RzX2RmKQogIGN0c19kZiA8LSBjdHNfZGZbY29tcGxldGUsIF0KCiAgdmFsdWVzX2RmIDwtIGN0c19kZlssIDY6bmNvbChjdHNfZGYpXSAlPiUgZHBseXI6OnNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkKICBjdHMgPC0gZ2V0X25yZWFkc19jb2x1bW5zKHZhbHVlc19kZikKCiAgY29uZGl0aW9uX2xhYmVscyA8LSBjKHJlcChsYWJlbF9jMSwgbGVuZ3RoKG1jb2xzKGdyYW5nZXNfYzEpKSksCiAgICAgICAgICAgICAgICAgICAgICAgIHJlcChsYWJlbF9jMiwgbGVuZ3RoKG1jb2xzKGdyYW5nZXNfYzIpKSkpCgoKICBjb2xkYXRhIDwtIGRhdGEuZnJhbWUoY29sbmFtZXMoY3RzKSwgY29uZGl0aW9uID0gYXMuZmFjdG9yKGNvbmRpdGlvbl9sYWJlbHMpKQoKICBkZHMgPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGN0cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IGNvbmRpdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dSYW5nZXMgPSBncmFuZ2VzX2MxW2NvbXBsZXRlLCBdKQoKCiAgaWYgKGVzdGltYXRlX3NpemVfZmFjdG9ycyA9PSBUUlVFKSB7CiAgICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKICB9CiAgZWxzZSB7CiAgICAjIFNpbmNlIGZpbGVzIGFyZSBzY2FsZWQsIHdlIGRvIG5vdCB3YW50IHRvIGVzdGltYXRlIHNpemUgZmFjdG9ycwogICAgc2l6ZUZhY3RvcnMoZGRzKSA8LSBjKHJlcCgxLCBuY29sKGN0cykpKQogIH0KCiAgZGRzIDwtIERFU2VxMjo6ZXN0aW1hdGVEaXNwZXJzaW9ucyhkZHMpCiAgZGRzIDwtIERFU2VxMjo6bmJpbm9tV2FsZFRlc3QoZGRzKQoKICBpZiAoYXNfZ3JhbmdlcykgewogICAgcmVzdWx0IDwtIERFU2VxMjo6cmVzdWx0cyhkZHMsIGZvcm1hdCA9ICJHUmFuZ2VzIixhbHBoYSA9IDAuMDEpCiAgICBpZiAoIWlzLm51bGwobmFtZXNfdmFsdWVzKSkgewogICAgICByZXN1bHQkbmFtZSA8LSBuYW1lc192YWx1ZXNbY29tcGxldGVdCiAgICB9CgogIH0KICBlbHNlIHsKICAgICMgcmVzdWx0IDwtIHJlc3VsdHMoZGRzLCBmb3JtYXQ9IkRhdGFGcmFtZSIpCiAgICByZXN1bHQgPC0gZGRzCiAgfQoKICByZXN1bHQKfQoKZ2V0X25yZWFkc19jb2x1bW5zIDwtIGZ1bmN0aW9uKGRmLCBsZW5ndGhfZmFjdG9yID0gMTAwKSB7CiAgIyBDb252ZXJ0IG1lYW4gY292ZXJhZ2VzIHRvIHJvdW5kIGludGVnZXIgcmVhZCBudW1iZXJzCiAgY3RzIDwtIGFzLm1hdHJpeChkZikKICBjdHMgPC0gYXMubWF0cml4KGN0c1tjb21wbGV0ZS5jYXNlcyhjdHMpLF0pCiAgY3RzIDwtIHJvdW5kKGN0cypsZW5ndGhfZmFjdG9yKQogIGN0cwp9CmBgYAoKYGBge3J9CgpwZWFrX3VuaXZlcnNlIDwtICIuLi9wZWFrcy9HNF9jb21iaW5lZF9taW4zcmVwLmJlZCIKCkJXcy5XVCA8LSBCV3NbZ3JlcCgiV1QiLEJXcyldCkJXcy5GQU5DSiA8LSBCV3NbZ3JlcCgiRDFENiIsQldzKV0KQldzLkRIWDM2IDwtIEJXc1tncmVwKCJQMkQyIixCV3MpXQpCV3MuREtPIDwtIEJXc1tncmVwKCJQM0Q0IixCV3MpXQogIAojIENhbGN1bGF0ZSBoZXJlIHNvbWUgbG9jaSBvciBiaW5zCmNvdi5XVCA8LSBid19sb2NpKEJXcy5XVCwgbG9jaSA9IHBlYWtfdW5pdmVyc2UpCmNvdi5ESFgzNiA8LSBid19sb2NpKEJXcy5ESFgzNiwgbG9jaSA9IHBlYWtfdW5pdmVyc2UpCmNvdi5GQU5DSiA8LSBid19sb2NpKEJXcy5GQU5DSiwgbG9jaSA9IHBlYWtfdW5pdmVyc2UpCmNvdi5ES08gPC0gYndfbG9jaShCV3MuREtPLCBsb2NpID0gcGVha191bml2ZXJzZSkKCmNvdi5XVCRuYW1lIDwtIHBhc3RlMCgicGVha18iLDE6bGVuZ3RoKGNvdi5XVCkpCmNvdi5ESFgzNiRuYW1lIDwtIHBhc3RlMCgicGVha18iLDE6bGVuZ3RoKGNvdi5ESFgzNikpCmNvdi5GQU5DSiRuYW1lIDwtIHBhc3RlMCgicGVha18iLDE6bGVuZ3RoKGNvdi5GQU5DSikpCmNvdi5ES08kbmFtZSA8LSBwYXN0ZTAoInBlYWtfIiwxOmxlbmd0aChjb3YuREtPKSkKYGBgCgpgYGB7cn0KZGlmZl9ESFgzNiA8LSBid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMoY292LldULCBjb3YuREhYMzYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV1QiLCAiREhYMzZLTyIpCmRpZmZfRkFOQ0ogPC0gYndfZ3Jhbmdlc19kaWZmX2FuYWx5c2lzKGNvdi5XVCwgY292LkZBTkNKLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldUIiwgIkZBTkNKIikKZGlmZl9ES08gPC0gYndfZ3Jhbmdlc19kaWZmX2FuYWx5c2lzKGNvdi5XVCwgY292LkRLTywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXVCIsICJES08iKQoKCiMgVGhpcyB0YWtlcyBjYXJlIG9mIGxvdyBjb250cyBhbmQgdGhpbmdzIGxpa2UgdGhpcywgYnV0IHlvdSBjYW4gYWxzbyB1c2UKIyBkaWZmX3Jlc3VsdHMgYXMgaXMgZm9yIHRoZSB0aGluZ3MgYmVsb3cKbGZjX0RIWDM2IDwtIERFU2VxMjo6bGZjU2hyaW5rKGRpZmZfREhYMzYsIGNvZWYgPSAiY29uZGl0aW9uX1dUX3ZzX0RIWDM2S08iLCB0eXBlPSJhcGVnbG0iKQpsZmNfRkFOQ0ogPC0gREVTZXEyOjpsZmNTaHJpbmsoZGlmZl9GQU5DSiwgY29lZiA9ICJjb25kaXRpb25fV1RfdnNfRkFOQ0oiLCB0eXBlPSJhcGVnbG0iKQpsZmNfREtPIDwtIERFU2VxMjo6bGZjU2hyaW5rKGRpZmZfREtPLCBjb2VmID0gImNvbmRpdGlvbl9XVF92c19ES08iLCB0eXBlPSJhcGVnbG0iKQoKZGF0YV9ESFgzNiA8LSBwbG90TUEobGZjX0RIWDM2LCByZXR1cm5EYXRhID0gVCkKZGF0YV9ESFgzNiRsZmMgPC0gLWRhdGFfREhYMzYkbGZjCmRhdGFfREhYMzYkbWVhbiA8LSBsb2cxMChkYXRhX0RIWDM2JG1lYW4pCgpkYXRhX0ZBTkNKIDwtIHBsb3RNQShsZmNfRkFOQ0osIHJldHVybkRhdGEgPSBUKQpkYXRhX0ZBTkNKJGxmYyA8LSAtZGF0YV9GQU5DSiRsZmMKZGF0YV9GQU5DSiRtZWFuIDwtIGxvZzEwKGRhdGFfRkFOQ0okbWVhbikKCmRhdGFfREtPIDwtIHBsb3RNQShsZmNfREtPLCByZXR1cm5EYXRhID0gVCkKZGF0YV9ES08kbGZjIDwtIC1kYXRhX0RLTyRsZmMKZGF0YV9ES08kbWVhbiA8LSBsb2cxMChkYXRhX0RLTyRtZWFuKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpnZ3NjYXR0ZXIoZGF0YV9ESFgzNix4ID0ibWVhbiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMV0pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpKQpwbG90X01BX0RIWDM2IDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ESFgzNiRjb3YuV1QgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuV1QpWyw2OjhdKQpkYXRhX0RIWDM2JGNvdi5ESFgzNiA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5ESFgzNilbLDY6OF0pCmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJjb3YuV1QiLHk9ImNvdi5ESFgzNiIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzFdKSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkKcGxvdF9YWV9ESFgzNiA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfREhYMzYkY292LldUIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LldUKVssNjo4XSkKZGF0YV9ESFgzNiRjb3YuREhYMzYgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuREhYMzYpWyw2OjhdKQpnZ3NjYXR0ZXIoZGF0YV9ESFgzNix4ID0iY292LldUIix5PSJjb3YuREhYMzYiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsxXSkpICsgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwLDUwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTAsNTApKSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKQpwbG90X1hZX0RIWDM2X3pvb20gPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZ2dzY2F0dGVyKGRhdGFfRkFOQ0oseCA9Im1lYW4iLHk9ImxmYyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzJdKSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSkKcGxvdF9NQV9GQU5DSiA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0ZBTkNKJGNvdi5XVCA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5XVClbLDY6OF0pCmRhdGFfRkFOQ0okY292LkZBTkNKIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LkZBTkNKKVssNjo4XSkKZ2dzY2F0dGVyKGRhdGFfRkFOQ0oseCA9ImNvdi5XVCIseT0iY292LkZBTkNKIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMl0pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkKcGxvdF9YWV9GQU5DSiA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpnZ3NjYXR0ZXIoZGF0YV9ES08seCA9Im1lYW4iLHk9ImxmYyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSkKcGxvdF9NQV9ES08gPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ES08kY292LldUIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LldUKVssNjo4XSkKZGF0YV9ES08kY292LkRLTyA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5ES08pWyw2OjhdKQpnZ3NjYXR0ZXIoZGF0YV9ES08seCA9ImNvdi5XVCIseT0iY292LkRLTyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2ciLGxpbWl0cyA9IGMoMC41LDQwMCkpICsgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2ciLGxpbWl0cyA9IGMoMC41LDQwMCkpICsgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpCnBsb3RfWFlfREtPIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfREtPJGxmY19ESFgzNiA8LSBkYXRhX0RIWDM2JGxmYwpkYXRhX0RLTyRsZmNfRkFOQ0ogPC0gZGF0YV9GQU5DSiRsZmMKZ2dzY2F0dGVyKGRhdGFfREtPLHggPSJsZmNfREhYMzYiLHk9ImxmYyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSkrIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSwgeGxpbT1jKC01LDUpKQpwbG90X0xGQ19ES09fdnNfREhYMzYgPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkKYGBgCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9Cmdnc2NhdHRlcihkYXRhX0RLTyx4ID0ibGZjX0ZBTkNKIix5PSJsZmMiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFszXSkpKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsNSksIHhsaW09YygtNSw1KSkKcGxvdF9MRkNfREtPX3ZzX0ZBTkNKIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApCmBgYApgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0RIWDM2JGxmY19ES08gPC0gZGF0YV9ES08kbGZjCmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJsZmMiLHk9ImxmY19ES08iLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsxXSkpKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsNSksIHhsaW09YygtNSw1KSkKYGBgCgpgYGB7cn0KYmVkIDwtIGFzLmRhdGEuZnJhbWUoY292LkRIWDM2KVssMTozXQoKcmVzdWx0c190YWJsZSA8LSBkYXRhLmZyYW1lKGNocj1iZWQkc2VxbmFtZXMsc3RhcnQ9YmVkJHN0YXJ0LGVuZD1iZWQkZW5kLG5hbWU9Y292LldUJG5hbWUsIGJhc2VNZWFuPWxmY19ES08kYmFzZU1lYW4sREhYMzY9ZGF0YV9ESFgzNiRpc0RFLEZBTkNKPWRhdGFfRkFOQ0okaXNERSxES089ZGF0YV9ES08kaXNERSxESFgzNmxmYz1kYXRhX0RIWDM2JGxmYyxGQU5DSmxmYz1kYXRhX0ZBTkNKJGxmYyxES09sZmM9ZGF0YV9ES08kbGZjLGRpcj0iLiIpCgpyZXN1bHRzX3RhYmxlJG5vbnNpZyA8LSAhKHJlc3VsdHNfdGFibGUkREhYMzYgfCByZXN1bHRzX3RhYmxlJEZBTkNKIHwgcmVzdWx0c190YWJsZSRES08pCgpyZXN1bHRzX3RhYmxlJHNpZyA8LSBmYWN0b3IoImxvd2xmYyIsIGxldmVscz1jKCJub25zaWciLCJsb3dsZmMiLCJGQU5DSiIsIkRIWDM2IiwiREtPIikpCnJlc3VsdHNfdGFibGUkc2lnWyhyZXN1bHRzX3RhYmxlJG5vbnNpZyldIDwtICJub25zaWciCnJlc3VsdHNfdGFibGUkc2lnWyhyZXN1bHRzX3RhYmxlJERLTyAmIHJlc3VsdHNfdGFibGUkREtPbGZjPjEpXSA8LSAiREtPIgpyZXN1bHRzX3RhYmxlJHNpZ1socmVzdWx0c190YWJsZSRESFgzNiAmIHJlc3VsdHNfdGFibGUkREhYMzZsZmM+MSldIDwtICJESFgzNiIKcmVzdWx0c190YWJsZSRzaWdbKHJlc3VsdHNfdGFibGUkRkFOQ0ogJiByZXN1bHRzX3RhYmxlJEZBTkNKbGZjPjEpXSA8LSAiRkFOQ0oiCgp3cml0ZS50YWJsZShyZXN1bHRzX3RhYmxlLCJHNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfcmVzdWx0cy50eHQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBULHF1b3RlID0gRiwgc2VwID0gIlx0IikKYGBgCgpgYGB7cn0KREhYMzZfYmVkIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkREhYMzYgJiByZXN1bHRzX3RhYmxlJERIWDM2bGZjPjEpLGMoMSwyLDMsNCw5LDEyKV0Kd3JpdGUudGFibGUoREhYMzZfYmVkLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfREhYMzZfc2lnLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKRkFOQ0pfYmVkIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkRkFOQ0ogJiByZXN1bHRzX3RhYmxlJEZBTkNKbGZjPjEpLGMoMSwyLDMsNCwxMCwxMildCndyaXRlLnRhYmxlKEZBTkNKX2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0ZBTkNKX3NpZy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCkRLT19iZWQgPC0gcmVzdWx0c190YWJsZVsocmVzdWx0c190YWJsZSRES08gJiByZXN1bHRzX3RhYmxlJERLT2xmYz4xKSxjKDEsMiwzLDQsMTEsMTIpXQp3cml0ZS50YWJsZShES09fYmVkLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfREtPX3NpZy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCm5vbnNpZ19iZWQgPC0gcmVzdWx0c190YWJsZVtyZXN1bHRzX3RhYmxlJG5vbnNpZyAsYygxLDIsMyw0LDExLDEyKV0Kd3JpdGUudGFibGUobm9uc2lnX2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX25vbnNpZy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCkRLT19iZWRfdG9wIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkREtPPT1UUlVFICYgcmVzdWx0c190YWJsZSRES09sZmM+MiAmIHJlc3VsdHNfdGFibGUkYmFzZU1lYW4gPiAxMDApLGMoMSwyLDMsNCwxMSwxMildCndyaXRlLnRhYmxlKERLT19iZWRfdG9wLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfREtPX3NpZ19sZmNfYmFzZV9jdXRvZmYuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgoKd3JpdGUudGFibGUoY2JpbmQocmVzdWx0c190YWJsZVssYygxLDIsMyldLHJlc3VsdHNfdGFibGUkc2lnLGFzLm51bWVyaWMocmVzdWx0c190YWJsZSRzaWcpLCIuIiksIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9zaWdfY2F0ZWdvcmllcy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpsaWJyYXJ5KGV1bGVycikKdiA8LSBsaXN0KERIWDM2PURIWDM2X2JlZCRuYW1lLEZBTkNKPUZBTkNKX2JlZCRuYW1lLERLTz1ES09fYmVkJG5hbWUpCnBsb3RfVmVubl9hbGwgPC0gcGxvdChldWxlcih2KSxxdWFudGl0aWVzPVQsIGJvcmRlcj0iYmxhY2siKQpwbG90X1Zlbm5fYWxsCmBgYApgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpsaWJyYXJ5KGV1bGVycikKREtPbmVnIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkREtPPT1UUlVFICYgcmVzdWx0c190YWJsZSRES09sZmM8IC0xKSxjKDQpXQp2IDwtIGxpc3QoYWxsPWNvdi5XVCRuYW1lLERLT25lZz1ES09uZWcsREtPPURLT19iZWQkbmFtZSkKcGxvdF9WZW5uX0RLTyA8LSBwbG90KGV1bGVyKHYpLHF1YW50aXRpZXM9VCkKcGxvdF9WZW5uX0RLTwpgYGAKYGBge3J9CmRpci5jcmVhdGUoIi4vcGxvdHMiLHNob3dXYXJuaW5ncyA9IEYpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX01BX0RIWDM2LnBkZiIscGxvdF9NQV9ESFgzNix3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTUFfRkFOQ0oucGRmIixwbG90X01BX0ZBTkNKLHdpZHRoID0gNCwgaGVpZ2h0PSA0KQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9NQV9ES08ucGRmIixwbG90X01BX0RLTyx3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTEZDX0RIWDM2LnBkZiIscGxvdF9MRkNfREtPX3ZzX0RIWDM2LHdpZHRoID0gNCwgaGVpZ2h0PSA0KQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9MRkNfRkFOQ0oucGRmIixwbG90X0xGQ19ES09fdnNfRkFOQ0osd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX1Zlbm5fS09zLnBkZiIscGxvdF9WZW5uX2FsbCx3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfVmVubl9ES09fdnNfYWxsLnBkZiIscGxvdF9WZW5uX0RLTyx3aWR0aCA9IDQsIGhlaWdodD0gNCkKYGBgIAoKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShjb3dwbG90KQpkaXIuY3JlYXRlKCIuL3BhbmVscyIsc2hvd1dhcm5pbmdzID0gRikKCmxpYnJhcnkoImNvd3Bsb3QiKQpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ESFgzNiwgeCA9IDAsIHkgPSAwLjUsIHdpZHRoID0gLjMzLCBoZWlnaHQgPSAuNSkgKwogIGRyYXdfcGxvdChwbG90X01BX0ZBTkNKLCB4ID0gLjMzLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ES08sIHggPSAwLjY2LCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfTEZDX0RLT192c19ESFgzNiwgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X0xGQ19ES09fdnNfRkFOQ0osIHggPSAwLjMzLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9WZW5uX2FsbCwgeCA9IDAuNjYsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiwiZCIsImUiLCJmIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC4zMywgMC42NiwgMCwgMC4zMywgMC42NiksIHkgPSBjKDEsIDEsIDEsIDAuNSwgMC41LCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtzX0RFU2VxMi5wZGYiLHApCmBgYCAKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShjb3dwbG90KQpkaXIuY3JlYXRlKCIuL3BhbmVscyIsc2hvd1dhcm5pbmdzID0gRikKCmxpYnJhcnkoImNvd3Bsb3QiKQpwIDwtIGdnZHJhdygpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ESFgzNiwgeCA9IDAsIHkgPSAwLjUsIHdpZHRoID0gLjMzLCBoZWlnaHQgPSAuNSkgKwogIGRyYXdfcGxvdChwbG90X01BX0ZBTkNKLCB4ID0gLjMzLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9ES08sIHggPSAwLjY2LCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfWFlfREhYMzYsIHggPSAwLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9YWV9GQU5DSiwgeCA9IDAuMzMsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X1hZX0RLTywgeCA9IDAuNjYsIHkgPSAwLCB3aWR0aCA9IDAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiwiZCIsImUiLCJmIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC4zMywgMC42NiwgMCwgMC4zMywgMC42NiksIHkgPSBjKDEsIDEsIDEsIDAuNSwgMC41LCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtzX0RFU2VxMl9zY2F0dGVyLnBkZiIscCkKYGBgIAoKYGBge3J9CmNvdiA8LSBjYmluZCggYXMuZGF0YS5mcmFtZShjb3YuV1QpWywxOjhdLCAKICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNvdi5ESFgzNilbLDY6OF0sIAogICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY292LkZBTkNKKVssNjo4XSwgCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShjb3YuREtPKVssNjo4XSkKCmNvbG5hbWVzKGNvdikgPC0gYyhjb2xuYW1lcyhjb3YpWzE6NV0sIldUMSIsIldUMiIsIldUMyIsIkRIWDEiLCJESFgyIiwiREhYMyIsIkZBTjEiLCJGQU4yIiwiRkFOMyIsIkRLTzEiLCJES08yIiwiREtPMyIpCgpyb3duYW1lcyhjb3YpIDwtIGFzLmRhdGEuZnJhbWUoY292LldUKSRuYW1lCgpjb3YkREhYMzZfc2lnIDwtIHJvd25hbWVzKGNvdikgJWluJSBESFgzNl9iZWQkbmFtZQpjb3YkRkFOQ0pfc2lnIDwtIHJvd25hbWVzKGNvdikgJWluJSBGQU5DSl9iZWQkbmFtZQpjb3YkREtPX3NpZyA8LSByb3duYW1lcyhjb3YpICVpbiUgREtPX2JlZCRuYW1lCmNvdiRub25fc2lnIDwtIHdpdGgoY292LCAhKERIWDM2X3NpZyB8IEZBTkNKX3NpZyB8IERLT19zaWcpKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CmxpYnJhcnkocmVzaGFwZTIpCm1kZiA8LSBtZWx0KGRhdGEuZnJhbWUobmFtZT1yb3duYW1lcyhjb3YpLGNvdlssNjoyMV0pKQptZGYgPC0gbWRmW21kZiR2YWx1ZTw1MDAsXQptZGYkY29uZCA8LSAiV1QiCm1kZiRjb25kW2dyZXAoIkRIWCIsbWRmJHZhcmlhYmxlKV0gPC0gIkRIWDM2LS8tIgptZGYkY29uZFtncmVwKCJGQU4iLG1kZiR2YXJpYWJsZSldIDwtICJGQU5DSi0vLSIKbWRmJGNvbmRbZ3JlcCgiREtPIixtZGYkdmFyaWFibGUpXSA8LSAiREhYMzYtLy1GQU5DSi0vLSIKcGxvdF92aW9sX3JlcF9hbGxfcGVha3MgPC0gZ2d2aW9saW4obWRmLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfYWxsX3BlYWtzCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF92aW9sX3JlcF9ESFgzNl9wZWFrcyA8LSBnZ3Zpb2xpbihtZGZbbWRmJERIWDM2X3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfREhYMzZfcGVha3MKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpnZ3Zpb2xpbihtZGZbbWRmJEZBTkNKX3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF92aW9sX3JlcF9ES09fcGVha3MgPC0gZ2d2aW9saW4obWRmW21kZiRES09fc2lnLF0sIHg9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUwKSkKcGxvdF92aW9sX3JlcF9ES09fcGVha3MKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzIDwtIGdndmlvbGluKG1kZlttZGYkbm9uX3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzCmBgYAoKYGBge3J9Cmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX3Zpb2xfcmVwX2FsbC5wZGYiLHBsb3RfdmlvbF9yZXBfYWxsX3BlYWtzKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl92aW9sX3JlcF9ES08ucGRmIixwbG90X3Zpb2xfcmVwX0RLT19wZWFrcykKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfdmlvbF9yZXBfREhYMzYucGRmIixwbG90X3Zpb2xfcmVwX0RIWDM2X3BlYWtzKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl92aW9sX3JlcF9ub25zaWcucGRmIixwbG90X3Zpb2xfcmVwX25vbnNpZ19wZWFrcykKYGBgIAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30Kc2RmIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IG5hbWUgKyBjb25kLCBkYXRhPW1kZiwgRlVOPSJtZWFuIikKc2RmJGNvbmQgPC0gZmFjdG9yKHNkZiRjb25kLGxldmVscz1jKCJXVCIsIkRIWDM2LS8tIiwiRkFOQ0otLy0iLCJESFgzNi0vLUZBTkNKLS8tIikpCmdndmlvbGluKHNkZiwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30Kc2RmJERIWDM2X3NpZyA8LSBzZGYkbmFtZSAlaW4lIERIWDM2X2JlZCRuYW1lCnNkZiRGQU5DSl9zaWcgPC0gc2RmJG5hbWUgJWluJSBGQU5DSl9iZWQkbmFtZQpzZGYkREtPX3NpZyA8LSBzZGYkbmFtZSAlaW4lIERLT19iZWQkbmFtZQpzZGYkREtPX3RvcCA8LSBzZGYkbmFtZSAlaW4lIERLT19iZWRfdG9wJG5hbWUKZ2d2aW9saW4oc2RmW3NkZiRESFgzNixdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpnZ3Zpb2xpbihzZGZbc2RmJEZBTkNKX3NpZyxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X3Zpb2xfREtPX3BlYWtzIDwtIGdndmlvbGluKHNkZltzZGYkREtPX3NpZyxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKcGxvdF92aW9sX0RLT19wZWFrcwpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CmdndmlvbGluKHNkZltzZGYkREtPX3RvcCxdLCB4PSJjb25kIix5PSJ2YWx1ZSIsZmlsbD0iY29uZCIscGFsZXR0ZSA9IG15cGFsW2MoNCwxLDIsMyldLCBhZGQ9Im1lYW5fc2QiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDc1KSkKYGBgCiMjIyBhbm5vdGF0ZSBwZWFrIHRhYmxlCmBgYHtyfQpsaWJyYXJ5KEdlbm9taWNSYW5nZXMpCgpiZWRfcGVha3MgPC0gcmVhZC5kZWxpbShwZWFrX3VuaXZlcnNlLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFKQpiZWRfY2htbSA8LSByZWFkLmRlbGltKGNocm9taG1tLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFKQoKIyBDcmVhdGUgR2Vub21pY1JhbmdlcyBvYmplY3RzIGZvciBCRUQgZmlsZXMKZ3JBIDwtIHdpdGgoYmVkX3BlYWtzLCBHUmFuZ2VzKFYxLCBJUmFuZ2VzKFYyLCBWMywgbmFtZXMgPSBWNCkpKQpnckIgPC0gd2l0aChiZWRfY2htbSwgR1JhbmdlcyhWMSwgSVJhbmdlcyhWMiwgVjMsbmFtZXMgPSBWNCkpKQoKIyBQZXJmb3JtIGludGVyc2VjdGlvbgppbnRlcnNlY3Rpb24gPC0gZmluZE92ZXJsYXBzKGdyQSwgZ3JCKQoKZm9yIChpIGluIHNlcV9hbG9uZyhnckEpKSB7CiAgcXVlcnlfZmVhdHVyZXMgPC0gcXVlcnlIaXRzKGludGVyc2VjdGlvbilbcXVlcnlIaXRzKGludGVyc2VjdGlvbikgPT0gaV0KICBvdmVybGFwcGluZ19mZWF0dXJlcyA8LSBzdWJqZWN0SGl0cyhpbnRlcnNlY3Rpb24pW3F1ZXJ5SGl0cyhpbnRlcnNlY3Rpb24pID09IGldCiAgCiAgaWYgKGxlbmd0aChvdmVybGFwcGluZ19mZWF0dXJlcykgPiAwKSB7CiAgICBvdmVybGFwcGluZ19pbnQgPC0gcGludGVyc2VjdChnckFbcXVlcnlfZmVhdHVyZXNdLCBnckJbb3ZlcmxhcHBpbmdfZmVhdHVyZXNdKQogICAgb3ZlcmxhcHBpbmdfd2lkdGhzIDwtIHdpZHRoKG92ZXJsYXBwaW5nX2ludCkKICAgIG1heF9vdmVybGFwX2luZGV4IDwtIG92ZXJsYXBwaW5nX2ZlYXR1cmVzW3doaWNoLm1heChvdmVybGFwcGluZ193aWR0aHMpXQogICAgbWF4X292ZXJsYXBfZmVhdHVyZSA8LSBnckJbbWF4X292ZXJsYXBfaW5kZXhdCiAgICAKICAgIGJlZF9wZWFrcyRWNFtpXSA8LSBuYW1lcyhtYXhfb3ZlcmxhcF9mZWF0dXJlKQogIH0KfQoKd3JpdGUudGFibGUoYmVkX3BlYWtzLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKYmVkX3BlYWtzX3RhYmxlIDwtIGNiaW5kKGJlZF9wZWFrcyxkYXRhLmZyYW1lKGJhc2VNZWFuPWxmY19ES08kYmFzZU1lYW4sREhYMzY9KGRhdGFfREhYMzYkaXNERSAmIGRhdGFfREhYMzYkbGZjPjEpLEZBTkNKPShkYXRhX0ZBTkNKJGlzREUgJiBkYXRhX0ZBTkNKJGxmYz4xKSxES089KGRhdGFfREtPJGlzREUmZGF0YV9ES08kbGZjPjEpLERIWDM2bGZjPWRhdGFfREhYMzYkbGZjLEZBTkNKbGZjPWRhdGFfRkFOQ0okbGZjLERLT2xmYz1kYXRhX0RLTyRsZmMpKQoKd3JpdGUudGFibGUoYmVkX3BlYWtzX3RhYmxlLCJHNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkLnR4dCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTJ9CiNyZWFkIGluIC0gaWYgeW91IHdhbnQgdG8gc2tpcCBkZSBub3ZvIGdlbmVyYXRpb24KYmVkX3BlYWtzX3RhYmxlIDwtIHJlYWQudGFibGUoIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9hbm5vdGF0ZWQudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKCnZwYWw9Y29sb3JSYW1wUGFsZXR0ZShjKCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiKSkKc3RhdHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkVjQpKQpnZ2RvbnV0Y2hhcnQoc3RhdHMseCA9ICJGcmVxIixsYWJlbD0iVmFyMSIsZmlsbD12cGFsKDEwKSkKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTN9CnZwYWw9Y29sb3JSYW1wUGFsZXR0ZShjKCJsaWdodGdyZWVuIiwiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJyZWQyIikpCgpzdGF0cyA8LSBkYXRhLmZyYW1lKGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJFY0KSksREhYMzY9YXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkVjRbYmVkX3BlYWtzX3RhYmxlJERIWDM2PT1UUlVFXSkpWzJdLEZBTkNKPWFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJFY0W2JlZF9wZWFrc190YWJsZSRGQU5DSj09VFJVRV0pKVsyXSxES089YXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkVjRbYmVkX3BlYWtzX3RhYmxlJERLTz09VFJVRV0pKVsyXSkKY29sbmFtZXMoc3RhdHMpIDwtIGMoIlN0YXRlIiwiVG90YWwiLCJESFgzNiIsIkZBTkNKIiwiREtPIikKCnN0YXRzJFRvdGFsPXN0YXRzJFRvdGFsL3N1bShzdGF0cyRUb3RhbCkqMTAwCnN0YXRzJERIWDM2PXN0YXRzJERIWDM2L3N1bShzdGF0cyRESFgzNikqMTAwCnN0YXRzJEZBTkNKPXN0YXRzJEZBTkNKL3N1bShzdGF0cyRGQU5DSikqMTAwCnN0YXRzJERLTz1zdGF0cyRES08vc3VtKHN0YXRzJERLTykqMTAwCm1kZiA8LSBtZWx0KHN0YXRzKQptZGYkU3RhdGUgPC0gZmFjdG9yKG1kZiRTdGF0ZSxsZXZlbHM9bGV2ZWxzKG1kZiRTdGF0ZSlbYygxLDMsNSw3LDQsNiwxMCw4LDksMildKQpjb2xzPWModnBhbCgxMSlbYyg0LDUsMywyLDksOCw3KV0sIiNEREREREQiLCIjRUVFRUVFIix2cGFsKDExKVsxMF0pCnBsb3RfYmFyX2Nocm9taG1tX2Fubm8gPC0gZ2diYXJwbG90KG1kZix4ID0gInZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iU3RhdGUiLHBhbGV0dGUgPWNvbHMpCnBsb3RfYmFyX2Nocm9taG1tX2Fubm8KYGBgCgoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfYmFyX2Nocm9taG1tX2Fubm8sIHggPSAwLCB5ID0gMCwgd2lkdGggPSAuMjAsIGhlaWdodCA9IDEpICsKICBkcmF3X3Bsb3QocGxvdF92aW9sX3JlcF9ES09fcGVha3MsIHggPSAuMiwgeSA9IDAsIHdpZHRoID0gLjQwLCBoZWlnaHQgPSAwLjcpICsKICBkcmF3X3Bsb3QocGxvdF92aW9sX3JlcF9ub25zaWdfcGVha3MsIHggPSAwLjYsIHkgPSAwLCB3aWR0aCA9IC40MCwgaGVpZ2h0ID0gMC43KSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiYSIsICJiIiwgImMiKSwgc2l6ZSA9IDE1LAogICAgICAgICAgICAgICAgICB4ID0gYygwLCAwLjIsIDAuNiksIHkgPSBjKDEsIDAuOCwgMC44KSkKcApnZ3NhdmUoInBhbmVscy9wZWFrX2Fubm9fdmlvbGluX3YxLnBkZiIscCkKYGBgIApgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zfQoKcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfYmFyX2Nocm9taG1tX2Fubm8sIHggPSAwLCB5ID0gMCwgd2lkdGggPSAuNCwgaGVpZ2h0ID0gMSkgKwogIGRyYXdfcGxvdChwbG90X3Zpb2xfcmVwX0RLT19wZWFrcywgeCA9IC40LCB5ID0gMC41LCB3aWR0aCA9IC42MCwgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzLCB4ID0gMC40LCB5ID0gMCwgd2lkdGggPSAuNjAsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC40LCAwLjQpLCB5ID0gYygxLCAxLCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtfYW5ub192aW9saW5fdjIucGRmIixwKQpgYGAgCg==